package simple.form.core;

import org.apache.log4j.Logger;
import simple.form.cache.Key;
import simple.form.controller.Request;
import simple.form.controller.Response;
import simple.form.core.annotation.ParameterBeanField;
import simple.form.utils.DateUtil;
import simple.form.utils.SafeConvertUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 请求参数转化为bean base
 * Created by Administrator on 2017/2/15.
 */
public class RequestBean<T> implements Key{
    public static Logger log4j = Logger.getLogger(RequestBean.class);
    protected HttpServletRequest request;
    protected HttpServletResponse response;

    /*请求的原始值*/
    protected Map<String,String> originalValue = new HashMap<>();

    /*验证后的消息*/
    protected Message  message;

    public RequestBean(){

    }
    public RequestBean(Request request){
        this.request = request.getRequest();
        this.originalValue = new HashMap<>();
        this.message = new Message();
    }

    public RequestBean(Request request,Response response){
        this.request = request.getRequest();
        this.response = response.getResponse();
        this.originalValue = new HashMap<>();
        this.message = new Message();
    }

    /**
     * 设置消息提示的方式
     * @param IsAlertMessage true:通过alert方式提示，否则通过tips方式提示
     */
    public void setIsAlert(boolean IsAlertMessage){
        this.message.setIsAlert(IsAlertMessage);
    }

    /**
     * 验证表单映射的bean是否通过
     * @return
     */
    public boolean isValidBean(){
        return this.getMessage().getStatus();
    }

    /**
     * 解析bean
     * @return
     */
    public static RequestBean parse(RequestBean bean){
        Class currentBean = bean.getClass();
        parse(currentBean,bean);
        return bean;
    }
    /**
     * 解析bean
     * @return
     */
    public static RequestBean parse(Class currentBean,RequestBean bean)  {
        HttpServletRequest request = bean.getRequest();
        Field[] fields = currentBean.getDeclaredFields();
        String fieldName;
        String fieldType;
        int type;
        for(Field field:fields) {
            field.setAccessible(true); //设置些属性是可以访问的
            fieldName = field.getName(); //得到此属性的名称
            fieldType = field.getType().toString();//得到此属性的类型
            type = ParameterBeanManager.type.get(fieldType);
            try {
                setBean(request,type,field,fieldName,bean);
            } catch (IllegalAccessException e) {
                log4j.error(e.getMessage());
                return null;
            }
        }
        checkBean(bean);
        return bean;
    }

    /**
     * 校验bean的字段值
     * @param bean
     */
    private static void checkBean(RequestBean bean) {
        Class currentBean = bean.getClass();
        Map<String,Map<String,Object>> fieldAnnotations = ParameterBeanManager.beanFieldAnnotation.get(currentBean);
        Field[] fields = currentBean.getDeclaredFields();
        String fieldName;
        //Map<"注解名称","注解值">
        Map<String,Object> fieldAnnotation=null;


        Map<String,Boolean> fieldError;
        for(Field field:fields) {
            field.setAccessible(true); //设置些属性是可以访问的
            fieldName = field.getName(); //得到此属性的名称
            fieldError = new HashMap<>();
            fieldError.put(fieldName,false);//默认没有错误

            if(fieldAnnotations!=null){
                fieldAnnotation = fieldAnnotations.get(fieldName);
            }
            if(fieldAnnotation!=null){
                Object fieldValue = null;
                try {
                    fieldValue  = field.get(bean);
                } catch (IllegalAccessException e) {
                    log4j.error(e.getMessage(),e);
                }
                final boolean[] isRegex = {false};
                final boolean[] isNull = {true};
                final boolean[] hasTip = {false};
                final String[] regex = new String[1];
                final String[] tip = new String[1];
                fieldAnnotation.forEach((k,v)->{
                    if(ParameterBeanField.IS_REGEX.equals(k)){
                        isRegex[0] = (boolean)v;

                    }
                    if(ParameterBeanField.REGEX.equals(k)){
                        regex[0]=(String)v;

                    }
                    if(ParameterBeanField.IS_NULL.equals(k)){
                        isNull[0] = (boolean)v;

                    }
                    if(ParameterBeanField.TIP.equals(k)){

                        if(v!=null||!v.toString().isEmpty()){
                            tip[0] = (String)v;
                            hasTip[0] = true;
                        }
                    }
                });
                //是否需要正则表达式验证
                if(isRegex[0]){
                    String regEx = SafeConvertUtil.toString(regex[0]);
                    Pattern pattern = Pattern.compile(regEx);
                    Matcher matcher = pattern.matcher(SafeConvertUtil.toString(bean.originalValue.get(fieldName)));
                    //正则匹配
                    if(!matcher.matches()){
                        fieldError.put(fieldName,true);
                    }
                }
                //如果当前验证通过了,则判断是否允许null
                if(fieldError.get(fieldName)!=true){
                    //是否允许null
                    if(!isNull[0]){
                        //如果为null则设置fieldError为true
                        if(fieldValue==null || SafeConvertUtil.toString(fieldValue).isEmpty()){
                            fieldError.put(fieldName, true);
                        }
                    }
                }
                //如果该字段有错误
                if(fieldError.get(fieldName)==true){
                    //有错，则设置消息状态为false
                    bean.message.setStatus(false);
                    //是否有错误提示
                    if(hasTip[0]){
                        //是否通过alert方式提示消息
                        if(bean.message.isAlert()){
                            bean.message.setAlertMessage(tip[0]);
                            break;
                        }else{
                            bean.message.getTipMessage().put(fieldName,tip[0]);
                        }
                    }

                }

            }

        }
    }

    /**
     * 设置bean的字段值
     * @param request
     * @param type  字段类型
     * @param field 字段
     * @param fieldName  字段的名称
     * @param bean bean对象
     * @throws IllegalAccessException
     */
    private static void setBean(HttpServletRequest request, int type, Field field,String fieldName, RequestBean bean) throws IllegalAccessException {
        //保存请求的原始值
        bean.originalValue.put(fieldName,request.getParameter(fieldName));
        //根据字段的类型设置bean字段的值
        switch (type){
            case ParameterBeanManager.BYTE :{
                field.set(bean, SafeConvertUtil.toByte(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.SHORT :{
                field.set(bean,SafeConvertUtil.toShort(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.INT :{
                field.set(bean,SafeConvertUtil.toInteger(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.LONG :{
                field.set(bean,SafeConvertUtil.toLong(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.FLOAT :{
                field.set(bean,SafeConvertUtil.toFloat(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.DOUBLE :{
                field.set(bean,SafeConvertUtil.toDouble(request.getParameter(fieldName)));
                break;
            }

            case ParameterBeanManager.BOOLEAN :{
                field.set(bean,SafeConvertUtil.toBoolean(request.getParameter(fieldName)));
                break;
            }

            case ParameterBeanManager.BYTE_CLASS :{
                field.set(bean,SafeConvertUtil.toByte(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.SHORT_CLASS :{
                field.set(bean,SafeConvertUtil.toShort(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.INT_CLASS :{
                field.set(bean,SafeConvertUtil.toInteger(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.LONG_CLASS :{
                field.set(bean,SafeConvertUtil.toLong(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.FLOAT_CLASS :{
                field.set(bean,SafeConvertUtil.toFloat(request.getParameter(fieldName)));
                break;
            }
            case ParameterBeanManager.DOUBLE_CLASS :{
                field.set(bean,SafeConvertUtil.toDouble(request.getParameter(fieldName)));
                break;
            }

            case ParameterBeanManager.BOOLEAN_CLASS :{
                field.set(bean,SafeConvertUtil.toBoolean(request.getParameter(fieldName)));
                break;
            }

            case ParameterBeanManager.STRING : {
                field.set(bean, SafeConvertUtil.toString(request.getParameter(fieldName)));
                break;
            }

            case ParameterBeanManager.DATE : {
                field.set(bean, DateUtil.parse(SafeConvertUtil.toString(request.getParameter(fieldName)), "yyyy-MM-dd"));
                break;
            }
            default: {
                throw new IllegalAccessException("no field type "+type);
            }
        }

    }

    /**
     * 解析bean
     * @return
     */
    public RequestBean<T> parse() {
        Class currentBean = this.getClass();
        Field[] fields = currentBean.getDeclaredFields();
        String fieldName;
        String fieldType;
        int type;
        for(Field field:fields){
            field.setAccessible(true); //设置些属性是可以访问的
            fieldName = field.getName(); //得到此属性的名称
            fieldType = field.getType().toString();//得到此属性的类型
            type = ParameterBeanManager.type.get(fieldType);
            try {
                setBean(this.request, type,field,fieldName, this);
            } catch (IllegalAccessException e) {
                log4j.error(e.getMessage());
            }
        }
        checkBean(this);
        return this;
    }
    public HttpServletRequest getRequest() {
        return request;
    }

    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }

    public HttpServletResponse getResponse() {
        return response;
    }

    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    @Override
    public String createKey() {
        return "";
    }
}
